/***************************************************************************

    machine.c

    Controls execution of the core MAME system.

****************************************************************************

    Copyright Aaron Giles
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in
          the documentation and/or other materials provided with the
          distribution.
        * Neither the name 'MAME' nor the names of its contributors may be
          used to endorse or promote products derived from this software
          without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

****************************************************************************

    Since there has been confusion in the past over the order of
    initialization and other such things, here it is, all spelled out
    as of January, 2008:

    main()
        - does platform-specific init
        - calls mame_execute() [mame.c]

        mame_execute() [mame.c]
            - calls mame_validitychecks() [validity.c] to perform validity checks on all compiled drivers
            - begins resource tracking (level 1)
            - calls create_machine [mame.c] to initialize the running_machine structure
            - calls init_machine() [mame.c]

            init_machine() [mame.c]
                - calls fileio_init() [fileio.c] to initialize file I/O info
                - calls config_init() [config.c] to initialize configuration system
                - calls input_init() [input.c] to initialize the input system
                - calls output_init() [output.c] to initialize the output system
                - calls state_init() [state.c] to initialize save state system
                - calls state_save_allow_registration() [state.c] to allow registrations
                - calls palette_init() [palette.c] to initialize palette system
                - calls render_init() [render.c] to initialize the rendering system
                - calls ui_init() [ui.c] to initialize the user interface
                - calls generic_machine_init() [machine/generic.c] to initialize generic machine structures
                - calls generic_video_init() [video/generic.c] to initialize generic video structures
                - calls generic_sound_init() [audio/generic.c] to initialize generic sound structures
                - calls timer_init() [timer.c] to reset the timer system
                - calls osd_init() [osdepend.h] to do platform-specific initialization
                - calls input_port_init() [inptport.c] to set up the input ports
                - calls rom_init() [romload.c] to load the game's ROMs
                - calls memory_init() [memory.c] to process the game's memory maps
                - calls watchdog_init() [watchdog.c] to initialize the watchdog system
                - calls the driver's DRIVER_INIT callback
                - calls device_list_start() [devintrf.c] to start any devices
                - calls video_init() [video.c] to start the video system
                - calls tilemap_init() [tilemap.c] to start the tilemap system
                - calls crosshair_init() [crsshair.c] to configure the crosshairs
                - calls sound_init() [sound.c] to start the audio system
                - calls debugger_init() [debugger.c] to set up the debugger
                - calls the driver's MACHINE_START, SOUND_START, and VIDEO_START callbacks
                - calls cheat_init() [cheat.c] to initialize the cheat system
                - calls image_init() [image.c] to initialize the image system

            - calls config_load_settings() [config.c] to load the configuration file
            - calls nvram_load [machine/generic.c] to load NVRAM
            - calls ui_display_startup_screens() [ui.c] to display the the startup screens
            - begins resource tracking (level 2)
            - calls soft_reset() [mame.c] to reset all systems

                -------------------( at this point, we're up and running )----------------------

            - calls scheduler->timeslice() [schedule.c] over and over until we exit
            - ends resource tracking (level 2), freeing all auto_mallocs and timers
            - calls the nvram_save() [machine/generic.c] to save NVRAM
            - calls config_save_settings() [config.c] to save the game's configuration
            - calls all registered exit routines [mame.c]
            - ends resource tracking (level 1), freeing all auto_mallocs and timers

        - exits the program

***************************************************************************/

#include "emu.h"
#include "emuopts.h"
#include "osdepend.h"
#include "config.h"
#include "debugger.h"
#include "image.h"
#include "profiler.h"
#include "render.h"
#include "cheat.h"
#include "ui.h"
#include "uimenu.h"
#include "uiinput.h"
#include "streams.h"
#include "crsshair.h"
#include "validity.h"
#include "debug/debugcon.h"
#include "hiscore.h"

#include <time.h>

#include "retromain.h"

/**************************************************************************
  GLOBAL VARIABLES
**************************************************************************/

/* a giant string buffer for temporary strings */
static char giant_string_buffer[65536] = { 0 };

int cpunum;


/**************************************************************************
  RUNNING MACHINE
**************************************************************************/

/*-------------------------------------------------
  running_machine - constructor
-------------------------------------------------*/

running_machine::running_machine(const game_driver &driver, const machine_config &_config, core_options &options, bool exit_to_game_select)
	: m_regionlist(m_respool),
	  m_devicelist(m_respool),
	  config(&_config),
	  m_config(_config),
	  firstcpu(NULL),
	  gamedrv(&driver),
	  m_game(driver),
	  primary_screen(NULL),
	  palette(NULL),
	  pens(NULL),
	  colortable(NULL),
	  shadow_table(NULL),
	  priority_bitmap(NULL),
	  sample_rate(options_get_int(&options, OPTION_SAMPLERATE)),
	  debug_flags(0),
      ui_active(false),
	  mame_data(NULL),
	  timer_data(NULL),
	  state_data(NULL),
	  memory_data(NULL),
	  palette_data(NULL),
	  tilemap_data(NULL),
	  streams_data(NULL),
	  devices_data(NULL),
	  romload_data(NULL),
	  sound_data(NULL),
	  input_data(NULL),
	  input_port_data(NULL),
	  ui_input_data(NULL),
	  cheat_data(NULL),
	  debugcpu_data(NULL),
	  generic_machine_data(NULL),
	  generic_video_data(NULL),
	  generic_audio_data(NULL),
	  m_debug_view(NULL),
	  driver_data(NULL),
	  m_logerror_list(NULL),
	  m_scheduler(*this),
	  m_options(options),
	  m_basename(driver.name),
	  m_current_phase(MACHINE_PHASE_PREINIT),
	  m_paused(false),
	  m_hard_reset_pending(false),
	  m_exit_pending(false),
	  m_exit_to_game_select(exit_to_game_select),
	  m_new_driver_pending(NULL),
	  m_soft_reset_timer(NULL),
	  m_saveload_schedule(SLS_NONE),
	  m_saveload_schedule_time(attotime_zero),
	  m_saveload_searchpath(NULL),
	  m_rand_seed(0x9d14abd7)
{
	memset(gfx, 0, sizeof(gfx));
	memset(&generic, 0, sizeof(generic));
	memset(m_notifier_list, 0, sizeof(m_notifier_list));
	memset(&m_base_time, 0, sizeof(m_base_time));

	/* attach this machine to all the devices in the configuration */
	m_devicelist.import_config_list(m_config.m_devicelist, *this);

	/* allocate the driver data (after devices) */
	if (m_config.m_driver_data_alloc != NULL)
		driver_data = (*m_config.m_driver_data_alloc)(*this);

	/* find devices */
	primary_screen = screen_first(*this);
	for (device_t *device = m_devicelist.first(); device != NULL; device = device->next())
		if (dynamic_cast<cpu_device *>(device) != NULL)
		{
			firstcpu = downcast<cpu_device *>(device);
			break;
		}
	cpu[0] = firstcpu;
	for (cpunum = 1; cpunum < ARRAY_LENGTH(cpu) && cpu[cpunum - 1] != NULL; cpunum++)
		cpu[cpunum] = cpu[cpunum - 1]->typenext();

	/* fetch core options */
	if (options_get_bool(&m_options, OPTION_DEBUG))
		debug_flags = (DEBUG_FLAG_ENABLED | DEBUG_FLAG_CALL_HOOK) | (options_get_bool(&m_options, OPTION_DEBUG_INTERNAL) ? 0 : DEBUG_FLAG_OSD_ENABLED);
}


/*-------------------------------------------------
  ~running_machine - destructor
-------------------------------------------------*/

running_machine::~running_machine()
{
	/* clear flag for added devices */
	options_set_bool(&m_options, OPTION_ADDED_DEVICE_OPTIONS, FALSE, OPTION_PRIORITY_CMDLINE);
}


/*-------------------------------------------------
  describe_context - return a string describing
  which device is currently executing and its
  PC
-------------------------------------------------*/

const char *running_machine::describe_context()
{
	device_execute_interface *executing = m_scheduler.currently_executing();
	if (executing != NULL)
	{
		cpu_device *cpu = downcast<cpu_device *>(&executing->device());
		if (cpu != NULL)
			retro_log(RETRO_LOG_INFO, "[MAME 2010] '%s' (%s)", cpu->tag(), core_i64_hex_format(cpu->pc(), cpu->space(AS_PROGRAM)->logaddrchars));
		else
			retro_log(RETRO_LOG_INFO, "[MAME 2010] '%s'", cpu->tag());
	}
	else
		m_context.cpy("(no context)");

	return m_context;
}


/*-------------------------------------------------
  start - initialize the emulated machine
-------------------------------------------------*/

void running_machine::start()
{
	/* initialize basic can't-fail systems here */
	fileio_init(this);
	config_init(this);
	input_init(this);
	output_init(this);
	state_init(this);
	state_save_allow_registration(this, true);
	palette_init(this);
	render_init(this);
	ui_init(this);
	generic_machine_init(this);
	generic_video_init(this);
	generic_sound_init(this);

	/* initialize the timers and allocate a soft_reset timer
	   this must be done before cpu_init so that CPU's can allocate timers */
	timer_init(this);
	m_soft_reset_timer = timer_alloc(this, static_soft_reset, NULL);

	/* init the osd layer */
	osd_init(this);

	/* initialize the base time (needed for doing record/playback) */
	time(&m_base_time);

	/* initialize the input system and input ports for the game
	   this must be done before memory_init in order to allow specifying
	   callbacks based on input port tags */
	time_t newbase = input_port_init(this, m_game.ipt);
	if (newbase != 0)
		m_base_time = newbase;

	/* intialize UI input */
	ui_input_init(this);

	/* initialize the streams engine before the sound devices start */
	streams_init(this);

	/* first load ROMs, then populate memory, and finally initialize CPUs
	   these operations must proceed in this order */
	rom_init(this);
	memory_init(this);
	watchdog_init(this);

	/* allocate the gfx elements prior to device initialization */
	gfx_init(this);

	/* initialize natural keyboard support */
	inputx_init(this);

	/* initialize image devices */
	image_init(this);

	/* start up the devices */
	m_devicelist.start_all();

	/* call the game driver's init function
	   this is where decryption is done and memory maps are altered
	   so this location in the init order is important */
	ui_set_startup_text(this, "Initializing...", true);
	if (m_game.driver_init != NULL)
		(*m_game.driver_init)(this);

	/* finish image devices init process */
	image_postdevice_init(this);

	/* start the video and audio hardware */
	video_init(this);
	tilemap_init(this);
	crosshair_init(this);

	sound_init(this);

	/* initialize the debugger */
	if ((debug_flags & DEBUG_FLAG_ENABLED) != 0)
		debugger_init(this);

	/* call the driver's _START callbacks */
	if (m_config.m_machine_start != NULL)
		(*m_config.m_machine_start)(this);
	if (m_config.m_sound_start != NULL)
		(*m_config.m_sound_start)(this);
	if (m_config.m_video_start != NULL)
		(*m_config.m_video_start)(this);

	/* set up the cheat engine */    
	cheat_init(this);
	/* set up the hiscore engine */    
    hiscore_init(this);

	/* disallow save state registrations starting here */
	state_save_allow_registration(this, false);
}


/*-------------------------------------------------
  run - execute the machine
-------------------------------------------------*/

int running_machine::run(bool firstrun)
{
   int error = MAMERR_NONE;

   /* move to the init phase */
   m_current_phase = MACHINE_PHASE_INIT;

   /* then finish setting up our local machine */
   start();

   /* load the configuration settings and NVRAM */
   config_load_settings(this);
   nvram_load(this);
   sound_mute(this, FALSE);

   /* display the startup screens */
   ui_display_startup_screens(this, firstrun, !options_get_bool(&m_options, OPTION_SKIP_NAGSCREEN));

   /* perform a soft reset -- this takes us to the running phase */
   soft_reset();

   /* run the CPUs until a reset or exit */
   m_hard_reset_pending = false;
   while ((!m_hard_reset_pending && !m_exit_pending) || m_saveload_schedule != SLS_NONE)
      return 0;

   return 0;
}

void running_machine::retro_machineexit()
{   
    retro_log(RETRO_LOG_INFO, "beginning retro_machineexit()\n");

   /* and out via the exit phase */
   m_current_phase = MACHINE_PHASE_EXIT;

   /* save the NVRAM and configuration */
   sound_mute(this, true);
   nvram_save(this);
   config_save_settings(this);
   
   /* call all exit callbacks registered */
   call_notifiers(MACHINE_NOTIFY_EXIT);

}

extern int RLOOP;
extern int ENDEXEC;

void running_machine::retro_loop()
{
   while (RLOOP==1)
   {
      /* execute CPUs if not paused */
      if (!m_paused)
         m_scheduler.timeslice();

      /* otherwise, just pump video updates through */
      else
         video_frame_update(this, false);

      /* handle save/load */
      if (m_saveload_schedule != SLS_NONE)
         handle_saveload();

   }

}

/*-------------------------------------------------
  schedule_exit - schedule a clean exit
-------------------------------------------------*/

void running_machine::schedule_exit()
{
	/* if we are in-game but we started with the select game menu, return to that instead */
	if (m_exit_to_game_select && options_get_string(&m_options, OPTION_GAMENAME)[0] != 0)
	{
		options_set_string(&m_options, OPTION_GAMENAME, "", OPTION_PRIORITY_CMDLINE);
		ui_menu_force_game_select(this, render_container_get_ui());
	}

	/* otherwise, exit for real */
	else
		m_exit_pending = true;

	/*  if we're executing, abort out immediately */
	m_scheduler.eat_all_cycles();

	/* if we're autosaving on exit, schedule a save as well */
    /*
	if (options_get_bool(&m_options, OPTION_AUTOSAVE) && (m_game.flags & GAME_SUPPORTS_SAVE))
		schedule_save("auto");
	*/
}


/*-------------------------------------------------
  schedule_hard_reset - schedule a hard-reset of
  the machine
-------------------------------------------------*/

void running_machine::schedule_hard_reset()
{
    retro_log(RETRO_LOG_INFO, "[MAME 2010] schedule_hard_reset for current MAME machine.\n");
    
	m_hard_reset_pending = true;

	/* if we're executing, abort out immediately */
	m_scheduler.eat_all_cycles();

    /* and out via the exit phase */
    m_current_phase = MACHINE_PHASE_EXIT;

    /* save the NVRAM and configuration */
    sound_mute(this, true);
    nvram_save(this);
    config_save_settings(this);

    /* call all exit callbacks registered */
    call_notifiers(MACHINE_NOTIFY_EXIT);

    ENDEXEC=1;
}


/*-------------------------------------------------
  schedule_soft_reset - schedule a soft-reset of
  the system
-------------------------------------------------*/

void running_machine::schedule_soft_reset()
{
    retro_log(RETRO_LOG_INFO, "[MAME 2010] schedule_soft_reset for current MAME machine.\n");
    
	timer_adjust_oneshot(m_soft_reset_timer, attotime_zero, 0);

	/* we can't be paused since the timer needs to fire */
	resume();

	/* if we're executing, abort out immediately */
	m_scheduler.eat_all_cycles();
}


/*-------------------------------------------------
  schedule_new_driver - schedule a new game to
  be loaded
-------------------------------------------------*/

void running_machine::schedule_new_driver(const game_driver &driver)
{
	m_hard_reset_pending = true;
	m_new_driver_pending = &driver;

	/* if we're executing, abort out immediately */
	m_scheduler.eat_all_cycles();
}

/*-------------------------------------------------
  pause - pause the system
-------------------------------------------------*/

void running_machine::pause()
{
	/* ignore if nothing has changed */
	if (m_paused)
		return;
	m_paused = true;

	/* call the callbacks */
	call_notifiers(MACHINE_NOTIFY_PAUSE);
}


/*-------------------------------------------------
  resume - resume the system
-------------------------------------------------*/

void running_machine::resume()
{
	/* ignore if nothing has changed */
	if (!m_paused)
		return;
	m_paused = false;

	/* call the callbacks */
	call_notifiers(MACHINE_NOTIFY_RESUME);
}


/*-------------------------------------------------
  region_alloc - allocates memory for a region
-------------------------------------------------*/

region_info *running_machine::region_alloc(const char *name, UINT32 length, UINT32 flags)
{
    /* make sure we don't have a region of the same name; also find the end of the list */
    region_info *info = m_regionlist.find(name);
    if (info != NULL)
		fatalerror("region_alloc called with duplicate region name \"%s\"\n", name);

	/* allocate the region */
	return m_regionlist.append(name, auto_alloc(this, region_info(*this, name, length, flags)));
}


/*-------------------------------------------------
  region_free - releases memory for a region
-------------------------------------------------*/

void running_machine::region_free(const char *name)
{
	m_regionlist.remove(name);
}


/*-------------------------------------------------
  add_notifier - add a notifier of the
  given type
-------------------------------------------------*/

void running_machine::add_notifier(machine_notification event, notify_callback callback)
{
	assert_always(m_current_phase == MACHINE_PHASE_INIT, "Can only call add_notifier at init time!");

	/* exit notifiers are added to the head, and executed in reverse order */
	if (event == MACHINE_NOTIFY_EXIT)
	{
		notifier_callback_item *notifier = auto_alloc(this, notifier_callback_item(callback));
		notifier->m_next = m_notifier_list[event];
		m_notifier_list[event] = notifier;
	}

	/* all other notifiers are added to the tail, and executed in the order registered */
	else
	{
		notifier_callback_item **tailptr;
		for (tailptr = &m_notifier_list[event]; *tailptr != NULL; tailptr = &(*tailptr)->m_next) ;
		*tailptr = auto_alloc(this, notifier_callback_item(callback));
	}
}


/*-------------------------------------------------
  add_logerror_callback - adds a callback to be
  called on logerror()
-------------------------------------------------*/

void running_machine::add_logerror_callback(logerror_callback callback)
{
	assert_always(m_current_phase == MACHINE_PHASE_INIT, "Can only call add_logerror_callback at init time!");

	logerror_callback_item **tailptr;
	for (tailptr = &m_logerror_list; *tailptr != NULL; tailptr = &(*tailptr)->m_next) ;
	*tailptr = auto_alloc(this, logerror_callback_item(callback));
}

/*-------------------------------------------------
  vlogerror - vprintf-style error logging
-------------------------------------------------*/

void CLIB_DECL running_machine::vlogerror(const char *format, va_list args)
{

    /* dump to the buffer */
    vsnprintf(giant_string_buffer, ARRAY_LENGTH(giant_string_buffer), format, args);
    static char buffer[1024];
    snprintf((char *)buffer, 1024, "[MAME 2010] %s", (char *)giant_string_buffer);
    retro_log(RETRO_LOG_INFO, buffer);
    
    /* log to all callbacks */
    for (logerror_callback_item *cb = m_logerror_list; cb != NULL; cb = cb->m_next)
        (*cb->m_func)(*this, giant_string_buffer);

}


/*-------------------------------------------------
  base_datetime - retrieve the time of the host
  system; useful for RTC implementations
-------------------------------------------------*/

void running_machine::base_datetime(system_time &systime)
{
	systime.set(m_base_time);
}


/*-------------------------------------------------
  current_datetime - retrieve the current time
  (offset by the base); useful for RTC
  implementations
-------------------------------------------------*/

void running_machine::current_datetime(system_time &systime)
{
	systime.set(m_base_time + timer_get_time(this).seconds);
}


/*-------------------------------------------------
  rand - standardized random numbers
-------------------------------------------------*/

UINT32 running_machine::rand()
{
	m_rand_seed = 1664525 * m_rand_seed + 1013904223;

	/* return rotated by 16 bits; the low bits have a short period
          and are frequently used */
	return (m_rand_seed >> 16) | (m_rand_seed << 16);
}


/*-------------------------------------------------
  call_notifiers - call notifiers of the given
  type
-------------------------------------------------*/

void running_machine::call_notifiers(machine_notification which)
{
	for (notifier_callback_item *cb = m_notifier_list[which]; cb != NULL; cb = cb->m_next)
		(*cb->m_func)(*this);
}


/*-------------------------------------------------
  handle_saveload - attempt to perform a save
  or load
-------------------------------------------------*/

void running_machine::handle_saveload()
{
	UINT32 openflags = (m_saveload_schedule == SLS_LOAD) ? OPEN_FLAG_READ : (OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
	const char *opnamed = (m_saveload_schedule == SLS_LOAD) ? "loaded" : "saved";
	const char *opname = (m_saveload_schedule == SLS_LOAD) ? "load" : "save";
	file_error filerr = FILERR_NONE;

	/* if no name, bail */
	if (m_saveload_pending_file.len() == 0)
		goto cancel;

	/* if there are anonymous timers, we can't save just yet, and we can't load yet either
	   because the timers might overwrite data we have loaded */
	if (timer_count_anonymous(this) > 0)
	{
		/* if more than a second has passed, we're probably screwed */
		if (attotime_sub(timer_get_time(this), m_saveload_schedule_time).seconds > 0)
		{
			popmessage("Unable to %s due to pending anonymous timers. See error.log for details.", opname);
			goto cancel;
		}
		return;
	}

	/* open the file */
	mame_file *file;
	filerr = mame_fopen(m_saveload_searchpath, m_saveload_pending_file, openflags, &file);
	if (filerr == FILERR_NONE)
	{
		astring fullname(mame_file_full_name(file));

		/* read/write the save state */
		state_save_error staterr = (m_saveload_schedule == SLS_LOAD) ? state_save_read_file(this, file) : state_save_write_file(this, file);

		/* handle the result */
		switch (staterr)
		{
			case STATERR_ILLEGAL_REGISTRATIONS:
				popmessage("Error: Unable to %s state due to illegal registrations. See error.log for details.", opname);
				break;

			case STATERR_INVALID_HEADER:
				popmessage("Error: Unable to %s state due to an invalid header. Make sure the save state is correct for this game.", opname);
				break;

			case STATERR_READ_ERROR:
				popmessage("Error: Unable to %s state due to a read error (file is likely corrupt).", opname);
				break;

			case STATERR_WRITE_ERROR:
				popmessage("Error: Unable to %s state due to a write error. Verify there is enough disk space.", opname);
				break;

			case STATERR_NONE:
				if (!(m_game.flags & GAME_SUPPORTS_SAVE))
					popmessage("State successfully %s.\nWarning: Save states are not officially supported for this game.", opnamed);
				else
					popmessage("State successfully %s.", opnamed);
				break;

			default:
				popmessage("Error: Unknown error during state %s.", opnamed);
				break;
		}

		/* close and perhaps delete the file */
		mame_fclose(file);
		if (staterr != STATERR_NONE && m_saveload_schedule == SLS_SAVE)
			osd_rmfile(fullname);
	}
	else
		popmessage("Error: Failed to open file for %s operation.", opname);

	/* unschedule the operation */
cancel:
	m_saveload_pending_file.reset();
	m_saveload_searchpath = NULL;
	m_saveload_schedule = SLS_NONE;
}


/*-------------------------------------------------
  soft_reset - actually perform a soft-reset
  of the system
-------------------------------------------------*/

TIMER_CALLBACK( running_machine::static_soft_reset ) { machine->soft_reset(); }

void running_machine::soft_reset()
{
	retro_log(RETRO_LOG_INFO, "[MAME 2010] Soft reset now.\n");

	/* temporarily in the reset phase */
	m_current_phase = MACHINE_PHASE_RESET;

	/* call all registered reset callbacks */
	call_notifiers(MACHINE_NOTIFY_RESET);

	/* run the driver's reset callbacks */
	if (m_config.m_machine_reset != NULL)
		(*m_config.m_machine_reset)(this);
	if (m_config.m_sound_reset != NULL)
		(*m_config.m_sound_reset)(this);
	if (m_config.m_video_reset != NULL)
		(*m_config.m_video_reset)(this);

	/* now we're running */
	m_current_phase = MACHINE_PHASE_RUNNING;

	/* allow 0-time queued callbacks to run before any CPUs execute */
	timer_execute_timers(this);
}


/*-------------------------------------------------
  logfile_callback - callback for logging to
  logfile
-------------------------------------------------*/

void running_machine::logfile_callback(running_machine &machine, const char *buffer)
{

}



/***************************************************************************
    MEMORY REGIONS
***************************************************************************/

/*-------------------------------------------------
  region_info - constructor
-------------------------------------------------*/

region_info::region_info(running_machine &machine, const char *name, UINT32 length, UINT32 flags)
	: m_machine(machine),
	  m_next(NULL),
	  m_name(name),
	  m_length(length),
	  m_flags(flags)
{
	m_base.u8 = auto_alloc_array(&machine, UINT8, length);
}


/*-------------------------------------------------
  ~region_info - destructor
-------------------------------------------------*/

region_info::~region_info()
{
	auto_free(&m_machine, m_base.v);
}



/**************************************************************************
  CALLBACK ITEMS
**************************************************************************/

/*-------------------------------------------------
  notifier_callback_item - constructor
-------------------------------------------------*/

running_machine::notifier_callback_item::notifier_callback_item(notify_callback func)
	: m_next(NULL),
	  m_func(func)
{
}


/*-------------------------------------------------
  logerror_callback_item - constructor
-------------------------------------------------*/

running_machine::logerror_callback_item::logerror_callback_item(logerror_callback func)
	: m_next(NULL),
	  m_func(func)
{
}



/**************************************************************************
  SYSTEM TIME
**************************************************************************/

/*-------------------------------------------------
  system_time - constructor
-------------------------------------------------*/

system_time::system_time()
{
	set(0);
}


/*-------------------------------------------------
  set - fills out a system_time structure
-------------------------------------------------*/

void system_time::set(time_t t)
{
	time = t;
	local_time.set(*localtime(&t));
	utc_time.set(*gmtime(&t));
}


/*-------------------------------------------------
  get_tm_time - converts a tm struction to a
  MAME mame_system_tm structure
-------------------------------------------------*/

void system_time::full_time::set(struct tm &t)
{
	second	= t.tm_sec;
	minute	= t.tm_min;
	hour	= t.tm_hour;
	mday	= t.tm_mday;
	month	= t.tm_mon;
	year	= t.tm_year + 1900;
	weekday	= t.tm_wday;
	day		= t.tm_yday;
	is_dst	= t.tm_isdst;
}